using System;
using System.Diagnostics;
using Sidewinder.Core.Interfaces;
using Sidewinder.Core.Interfaces.Entities;
using Wolfpack.Core;
using Wolfpack.Core.Interfaces.Entities;
using Wolfpack.Core.Notification;
using Wolfpack.Core.Publishers;

namespace Wolfpack.Contrib.Deployment
{
    /// <summary>
    /// This will download a nuget package if a new version is available.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class DeploymentPublisherBase<T> : FilteredResultPublisherBase<T>
        where T: DeploymentConfig
    {
        public IPipelineStep<UpdaterContext> Updater { get; set; }

        protected PluginDescriptor Identity { get { return _identity ?? (_identity = BuildMessageIdentity()); }}

        private PluginDescriptor _identity;

        protected DeploymentPublisherBase(T config) : base(config, config.TargetHealthCheckName)
        {
            if (string.IsNullOrWhiteSpace(config.Feed))
                config.Feed = Sidewinder.Core.Constants.NuGet.OfficialFeedUrl;

            Updater = new Sidewinder.Core.Updater.GetNuGetPackages();
        }

        protected override void Publish(NotificationEvent notification)
        {
            // ignore critical failures & logical failures - no use to us!
            if (notification.CriticalFailure || !notification.Result.GetValueOrDefault(false))
                return;

            var timer = new Stopwatch();
            UpdaterContext updaterContext;

            try
            {
                timer.Start();

                if (!DownloadPackage(notification, out updaterContext))
                {
                    // failed - do something here?
                    Logger.Info(
                        "*** Deployment publisher '{0}' was launched but did not detect any updates to package '{1}' ***",
                        Config.FriendlyId,
                        Config.PackageId);
                    return;
                }
            }
            finally
            {
                timer.Stop();
            }

            PostDownloadAction(notification, updaterContext, timer.Elapsed);
        }

        /// <summary>
        /// Download package from nuget feed, this will also unpack the nuget package
        /// into the folder specified in the config
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        protected virtual bool DownloadPackage(NotificationEvent notification, out UpdaterContext context)
        {
            var package = new TargetPackages();
            package.Add(new TargetPackage
            {
                Name = Config.PackageId,
                NuGetFeedUrl = Config.Feed,
                UpdateDependencies = true
            });

            context = new UpdaterContext
            {
                Config = new UpdateConfig
                {
                    DownloadFolder = SmartLocation.GetLocation(Config.DownloadFolder),
                    TargetPackages = package
                }
            };

            return Updater.Execute(context);
        }

        protected virtual void PostDownloadAction(NotificationEvent notification, UpdaterContext updateContext, TimeSpan deployDuration)
        {
            // Send a notification that package installed
            var msg = HealthCheckData.For(Identity, "Successfully deployed package {0} v{1} to {2}",
                                    updateContext.Updates[0].Target.Name,
                                    updateContext.Updates[0].NewVersion,
                                    updateContext.Config.DownloadFolder)
                    .AddTag(updateContext.Updates[0].Target.Name)
                    .SetDuration(deployDuration)
                    .Succeeded();

            Messenger.Publish(NotificationRequestBuilder.For(Config.NotificationMode, msg).Build());
        }

        protected abstract PluginDescriptor BuildMessageIdentity();
    }
}